﻿namespace Contoso.ActiveDirectory {

    #region Usings
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.DirectoryServices;
    using System.Threading;
    using System.Diagnostics;
    #endregion

    /// <summary>
    /// When querying for a SiteLink, the base DN must be the Configuration Naming Context
    /// </summary>
    [Serializable]
    public class SiteLink : ADBaseObjectProperties {

        #region Members
        #region Fields
        public static readonly new string[] AttributesToGet;

        public static readonly string ObjectCategoryShortName = "SiteLink"; 
        #endregion

        public int Cost { get; private set; }

        public InstanceTypeFlags InstanceType { get { return instanceType; } }
        private InstanceTypeFlags instanceType;

        public SiteLinkOptions Options { get { return options; } }
        private SiteLinkOptions options;

        public int ReplInterval { get; private set; }

        public IReadOnlyList<string> SiteList { get; private set; }

        #endregion

        #region Constructors
        static SiteLink() {
            var attributesToGet = new List<string>();
            attributesToGet.AddRange(new string[]
            {
                "cost",
                "replInterval",
                "siteList"
            });

            attributesToGet.AddRange(ADBaseObjectProperties.AttributesToGet);

            AttributesToGet = attributesToGet.Distinct().ToArray();
            attributesToGet = null;
        }
        public SiteLink() {
            this.Initialize();
        }

        public SiteLink(DirectoryEntry directoryEntry, bool destroyInputObject = true)
            : base(directoryEntry, destroyInputObject) {
                if (this.GetType().Name == typeof(SiteLink).Name) {
                this.Attributes = null;
            }
        }

        public SiteLink(SearchResult result, bool destroyInputObject = true)
            : base(result, destroyInputObject) {
                if (this.GetType().Name == typeof(SiteLink).Name) {
                this.Attributes = null;
            }
        }

        public SiteLink(List<string> ldifOutput)
            : base(ldifOutput) {
                if (this.GetType().Name == typeof(SiteLink).Name) {
                this.Attributes = null;
            }
        }
        #endregion

        #region Methods
        protected override void Initialize() {
            base.Initialize();

            this.SiteList = new List<string>();
        }
        protected override void ProcessResults() {

            try {
                base.ProcessResults();

                if (this.Attributes.ContainsKey("cost")) {
                    this.Cost = Convert.ToInt32(this.Attributes["cost"][0]);
                }
                if (this.Attributes.ContainsKey("options")) {
                    Enum.TryParse<SiteLinkOptions>(this.Attributes["options"][0].ToString(), result: out options);
                }
                if (this.Attributes.ContainsKey("instanceType")) {
                    Enum.TryParse<InstanceTypeFlags>(this.Attributes["instanceType"][0].ToString(), result: out instanceType);
                }
                if (this.Attributes.ContainsKey("replInterval")) {
                    this.ReplInterval = Convert.ToInt32(this.Attributes["replInterval"][0]);
                }
                this.SiteList = ADDataAccess.GetMultiValuedAttribute<string>("siteList", this.Attributes);

                this.IsValid = !string.IsNullOrWhiteSpace(this.DN)
                    && this.ObjectClass.Any(x => string.Equals(x, ObjectCategoryShortName, StringComparison.OrdinalIgnoreCase));            
            }
            catch (Exception e) {
                Debug.WriteLine(string.Format("{0}  [ThreadID: {1}]  {2} Error: {3}", DateTime.Now.TimeOfDay, Thread.CurrentThread.ManagedThreadId, CustomExtensions.CurrentMethodName(), e.VerboseExceptionString()));
                throw;
            }
        }
        public string ToFormattedString() {
            var info = new StringBuilder();

            info.AppendLine(string.Format("SiteLink: {0}", this.Name ?? "NULL"));

            return info.ToString();
        }
        #endregion
    }
}
